﻿using log4net;
using NVelocity;
using NVelocity.App;
using NVelocity.Exception;
using System.Reflection;
using Koala.Pro.CodeGenerator.UI.DatabaseModel.Schema;
using Koala.Pro.CodeGenerator.UI.Models;

namespace Koala.Pro.CodeGenerator.UI.Common.Adapter
{
    public interface IAdapter
    {
        void Execute();

        List<FileNameAndCode> ExecuteString();
    }

    public abstract class AbstractAdapter : IAdapter
    {
        protected DatabaseInfo database;

        protected List<string> selectedTableNames = new List<string>();

        protected VelocityContext context;

        protected Template template;

        protected MainSetting mainSetting = new MainSetting();

        protected static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        protected string templateFile;

        private string fileExtension = ".cs";

        private string directoryOfOutput = "Common";

        private string fileNameOfOutput;

        public string DirectoryOfOutput
        {
            get
            {
                return directoryOfOutput;
            }
            set
            {
                directoryOfOutput = value;
            }
        }

        public string FileNameOfOutput
        {
            get
            {
                return fileNameOfOutput;
            }
            set
            {
                fileNameOfOutput = value;
            }
        }

        public string FileExtension
        {
            get
            {
                return fileExtension;
            }
            set
            {
                fileExtension = value;
            }
        }

        public AbstractAdapter(DatabaseInfo database, List<string> selectedTableNames, string templateFile)
        {
            if (templateFile == null)
            {
                log.Error("Invalid parameter of templateFile.");
                throw new ArgumentException("Invalid parameter of templateFile.", "templateFile");
            }
            this.database = database;
            this.selectedTableNames = selectedTableNames;
            this.templateFile = templateFile;
            mainSetting.Load();
            InitTemplateEngine();
            if (this.database != null)
            {
                context.Put("DatabaseInfo", database);
            }
            fileNameOfOutput = GetFileNameFromTemplate(templateFile);
            directoryOfOutput = "Common";
        }

        public AbstractAdapter(string templateFile)
            : this(null, null, templateFile)
        {
        }

        public virtual void Execute()
        {
        }

        public virtual List<FileNameAndCode> ExecuteString()
        {
            return null;
        }

        public virtual void OutputFile()
        {
            if (template != null)
            {
                string filePath = AdapterUtil.GetOutputPath(mainSetting.OutputDir, mainSetting.RootNameSpace);
                filePath += AdapterUtil.CheckEndBySlash(directoryOfOutput);
                string text = filePath + fileNameOfOutput + fileExtension;
                DirectoryInfo directoryInfo = new DirectoryInfo(filePath);
                if (!directoryInfo.Exists)
                {
                    directoryInfo.Create();
                }
                log.Debug(string.Format("Class file output path:{0}", text));
                using (StreamWriter writer = new StreamWriter(text, false))
                {
                    template.Merge(context, writer);
                }
            }
        }

        public virtual string OutputString()
        {
            string result = string.Empty;
            if (template != null)
            {
                using (StringWriter stringWriter = new StringWriter())
                {
                    template.Merge(context, stringWriter);
                    result = stringWriter.GetStringBuilder().ToString();
                }
            }
            return result;
        }

        protected void InitTemplateEngine()
        {
            Velocity.Init();
            context = new VelocityContext();
            try
            {
                template = Velocity.GetTemplate(templateFile);
            }
            catch (ResourceNotFoundException innerException)
            {
                string message = string.Format("Cannot find template " + templateFile);
                log.Error(message);
                throw new Exception(message, innerException);
            }
            catch (ParseErrorException ex)
            {
                string message2 = string.Format("Syntax error in template " + templateFile + ":" + ex.StackTrace);
                log.Error(message2);
                throw new Exception(message2, ex);
            }
            context.Put("RootNameSpace", mainSetting.RootNameSpace);
        }

        private string GetFileNameFromTemplate(string templateFileName)
        {
            int num = templateFileName.LastIndexOf('/');
            int num2 = templateFileName.LastIndexOf('\\');
            int num3 = num > num2 ? num : num2;
            int num4 = templateFileName.IndexOf('.');
            if (num3 < num4)
            {
                return templateFileName.Substring(num3 + 1, num4 - num3 - 1);
            }
            return templateFileName.Substring(num3);
        }
    }

}
